#!/usr/bin/env python
# encoding: utf-8

#  Copyright (c) 2007 Freight Logistics, Inc.
#  Author Ryan Parrish <rparrish@freightlogistics.com>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import os
import sys
import md5
import cPickle as pickle


import MySQLdb
import pysvn


#TODO: start using this more compact dict
CONTENT = dict(form = dict(name = 37),
               table = dict(name = 46, value = 47),
               form_method = dict(name = 137, value = 138),
               global_method = dict(name = 137, value = 138),
               calc = dict(name = 140, value = 141))

CONTENT_ID = {'form_name':37,
              'table_name':46,
              'table_value':47,
              'form_method_name':137,
              'form_method_value':138,
              'global_method_name':137,
              'global_method_value':138,
              'calc_name':140,
              'calc_value':141}

class ServoyVCS:
    
    def __init__(self, config):
        self.CONFIG = config
        self._connect_db()
        
    def _connect_db(self):
        __doc__ = "connect to the chosen RMBDS"
        self.db = MySQLdb.connect(host=self.CONFIG['DB_HOST'], 
                                    user=self.CONFIG['DB_USER'],
                                    passwd=self.CONFIG['DB_PASS'],
                                    db=self.CONFIG['DB_SCHEMA'])
        
    def get_elements(self, solution, elementType):
        __doc__ = ""
        
        if elementType == 'global_method_name':
            sql = """
            SELECT
                element_property_id,
                element_id,
                revision,
            	property_value
            FROM 
                servoy_element_properties 
            WHERE 
                element_id IN (SELECT element_id FROM servoy_elements WHERE parent_element_id IN
            		(SELECT element_id FROM servoy_element_properties WHERE property_value = "%s")
            	AND object_type_id = 24)
            AND content_id = %s
            ORDER BY revision ASC""" % (solution, CONTENT_ID[elementType])
        elif elementType == 'form_method_name':
            sql = """
            SELECT
                element_property_id,
            	element_id,
            	revision,
            	property_value
            FROM 
            	servoy_element_properties 
            WHERE 
            	element_id IN (SELECT element_id FROM servoy_elements WHERE parent_element_id IN
            		(SELECT element_id FROM servoy_elements WHERE parent_element_id IN
            			(SELECT element_id FROM servoy_element_properties WHERE property_value = "%s")
            		AND object_type_id = 3)
            	AND object_type_id = 24)
            AND content_id = %s
            ORDER BY revision ASC""" % (solution, CONTENT_ID[elementType])
        elif elementType == 'table_name' or 'calc_name' or 'form_name':
            sql = """
            SELECT 
                element_property_id,
            	element_id,
            	revision,
            	property_value
            FROM 
                servoy_element_properties 
            WHERE content_id = %s""" % (CONTENT_ID[elementType])
            
        cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute(sql)
        result = cursor.fetchall()
        
        parentSQL = """
        SELECT 
            parent_element_id 
        FROM 
            servoy_elements 
        WHERE element_id = %d
        AND revision = %d"""
        
        elements = dict()
        for row in result:
            cursor.execute(parentSQL % (row['element_id'], row['revision']))
            parent_element_id = cursor.fetchone()['parent_element_id']
            
            if elements.has_key(row['element_id']):
                element = elements[row['element_id']]
            else:
                elements[row['element_id']] = dict()
                element = elements[row['element_id']]
                element['property_value'] = row['property_value']
                element['parent_element_id'] = parent_element_id
                element['revisions'] = list()
            
            x = dict()
            x['element_property_id'] = int(row['element_property_id'])
            x['revision'] = int(row['revision'])
            element['revisions'].append(x)
         
        cursor.close()
        return elements
        
    def get_parent_form(self, solution, methodElemID):
        sql = """
        SELECT property_value as form_name FROM servoy_element_properties WHERE element_id IN
        	(SELECT element_id FROM servoy_elements WHERE parent_element_id IN
        		(SELECT element_id FROM servoy_element_properties WHERE property_value = "%s") 
        	AND object_type_id = 3)
        AND content_id = %d AND element_id = %d""" % (solution, 
                                                        CONTENT['form']['name'],
                                                        methodElemID)
        
        cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute(sql)
        
        return cursor.fetchone()
        
    def get_method_text(self, elementType, elementID):
        __doc__ = """gets text for a method"""
        args = dict(elementType = elementType, 
                    elementID = elementID,
                    contentID = CONTENT[elementType]['value'])
        sql = """
        SELECT 
            property_value
        FROM 
            servoy_element_properties 
        WHERE content_id = %(contentID)d 
        AND element_id = %(elementID)d
        AND revision = (SELECT 
                            revision
                        FROM 
                            servoy_element_properties
                        WHERE content_id = %(contentID)d 
                            AND element_id = %(elementID)d
                        ORDER BY revision DESC
                        LIMIT 1)"""
	print sql % args

        cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
        resultCount = cursor.execute(sql % args)
        if resultCount > 1:
            print 'element_id %d has a sequence pair, aborting.' % elementID
            return 'This method is greater than 32K and thus was not exported \
            do not attempt to modify this function outside servoy developer'
        result = cursor.fetchone()
        cursor.close()
        
        if result is None:
            print 'element_id %s does not have any value' % elementID
            return ''
        return result['property_value']
        
    def _write_property_to_db(self):
    	self.propertyValue = MySQLdb.escape_string(self.propertyValue)
        sql = """
        UPDATE 
            servoy_element_properties 
        SET property_value = "%s" 
        WHERE content_id = %d 
            AND element_id = %d 
            AND revision = %d""" % (self.propertyValue,
                                    CONTENT[self.metaData['elementType']]['value'],
                                    self.metaData['elementID'],
                                    self.metaData['revision'])
	print sql
        cursor = self.db.cursor()
        cursor.execute(sql)
        self.db.commit()
        cursor.close()
        
    def _update_mainline_file(self):
        __doc__="""pulls the property value from the db and writes the file"""
        text = self.get_method_text(self.metaData['elementType'], 
                                        self.metaData['elementID'])
        methodFile = open(self.pathInRepo, 'w')
        methodFile.write(text)
        methodFile.close()
        
    def _commit_mainline(self, commitMessage):
        client = pysvn.Client()
        client.checkin(self.pathInRepo, commitMessage)
        
    def commit_method(self, metaData, commitMessage):
        __doc__ = """takes a updated method text and updates the DB, and 
        updates the mainline"""
        
        #TODO: check to see if the file has been commited to the local branch    
        
        self.metaData = metaData['metaData']
        self.propertyValue = metaData['propertyValue']
        self.pathInRepo = self.CONFIG['EXPORT_PATH'] + '/' + self.metaData['methodPath'] + '.servoy'
        
        print self.metaData

        self._write_property_to_db()
        self._update_mainline_file()
        self._commit_mainline(commitMessage)
        self._flush_solution() #place holder
        
    def _flush_solution(self):
        __doc__="""flush the solution via the admin web inteface"""
        pass
        
    def write_method(self, methodText, metaData, folder='.'):
        __doc__ = """writes the text file containing the methods text along with
        a metadata file containing the methods element_id in the servoy_repository."""
        methodfile = file('%s/%s.servoy' % (folder, metaData['methodName']), 'w')
        metafile = file('%s/.%s' % (folder, metaData['methodName']), 'wb')
            
        methodfile.write(methodText)
        methodfile.close()
        
        pickle.dump(metaData, metafile, True)

        metafile.close()
        
    def check_status(self, elementPropID):
    	__doc__ = "quick check to see if element still is in the repo"
    	sql = """SELECT element_property_id 
		 FROM servoy_element_properties
		 WHERE element_property_id = %d"""
	cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
	result = cursor.execute(sql % elementPropID)

	if result == 0:
	    return False
	else:
	    return True
    	
    @staticmethod
    def get_property_data(updatedProperty):
        __doc__ = """Pass the full path to the update method file to get back a 
        dictionary containing the servoy_repo element_id and text content of the
        updated method file so these values can be updated in the DB"""
        if updatedProperty[0] != '/':
            updatedProperty = os.getcwd() + '/' + updatedProperty

        folder = '/'.join(updatedProperty.split('/')[:-1])
        method = updatedProperty.split('/')[-1].split('.')[0]

        metaDataFile = open(folder + '/.' + method, 'rb')
        metaData = pickle.load(metaDataFile)

        methodFile = open(updatedProperty, 'r')
        propertyValue = methodFile.read()
        methodFile.close()

        return dict(metaData = metaData, propertyValue=propertyValue)
